﻿namespace CgSilverlightDynamicGeometry
{
    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using CgSilverlightDynamicGeometry.Utilities;
    using System.Collections.Generic;
    using System.Linq;
    using M = System.Math;

    public class CoordinateSystem
    {
        public Drawing Drawing { get; set; }

        public CoordinateSystem(Drawing dw)
        {
            Drawing = dw;
            Init();
        }

        public void Init()
        {
            UnitLength = 48;
            Origin = (new Point(Drawing.Canvas.ActualWidth,3)).Scale(0.5).SnapToIntegers().Minus(0.5);
        }

        /// <summary>
        /// 可显示范围
        /// </summary>
        public Point PhysicalSize
        {
            get
            {
                return new Point(Drawing.Canvas.ActualWidth, Drawing.Canvas.ActualHeight);
            }
        }

        private double unitLength;
        /// <summary>
        /// 单位像素长度
        /// </summary>
        public double UnitLength
        {
            get { return unitLength; }
            set {
                if (value < 30 || value > 100)
                {
                    return;
                }
                unitLength = value;
                Recalculate();
            }
        }

        private Point[] LogicalViewportVertices { get; set; }
        /// <summary>
        /// 更新显示
        /// </summary>
        public void Recalculate()
        {
            LogicalViewportVertices = GetViewportVerticesInLogical();
            if (LogicalViewportVertices != null)
            {
                MinimalVisibleX = LogicalViewportVertices.Min(p => p.X);
                MinimalVisibleY = LogicalViewportVertices.Min(p => p.Y);
                MaximalVisibleX = LogicalViewportVertices.Max(p => p.X);
                MaximalVisibleY = LogicalViewportVertices.Max(p => p.Y);
                Drawing.CartesianGrid.UpdateVisual();
            }
        }

        public Point[] GetViewportVerticesInLogical()
        {
            Point[] result = new Point[4];
            var physicalSize = PhysicalSize;
            if (!physicalSize.X.IsValidPositiveValue() || !physicalSize.Y.IsValidPositiveValue())
            {
                return LogicalViewportVertices;
            }

            result[0] = ToLogical(new Point());
            result[1] = ToLogical(new Point(physicalSize.X, 0));
            result[2] = ToLogical(new Point(physicalSize.X, physicalSize.Y));
            result[3] = ToLogical(new Point(0, physicalSize.Y));
            return result;
        }

        /// <summary>
        /// 显示点转换坐标点
        /// </summary>
        /// <param name="physicalPoint">显示点</param>
        /// <returns>坐标点</returns>
        public virtual Point ToLogical(Point physicalPoint)
        {
            return new Point(
                (physicalPoint.X - Origin.X) / UnitLength,
                -(physicalPoint.Y - Origin.Y) / UnitLength).RoundToEpsilon();
        }

        /// <summary>
        /// 坐标点转换为显示点
        /// </summary>
        /// <param name="logicalPoint"></param>
        /// <returns></returns>
        public virtual Point ToPhysical(Point logicalPoint)
        {
            return new Point(
                origin.X + logicalPoint.X * unitLength,
                origin.Y - logicalPoint.Y * unitLength);
        }

        private Point origin;
        /// <summary>
        /// 原点
        /// </summary>
        public Point Origin
        {
            get { return origin; }
            private set
            {
                origin = value;
                Recalculate();
            }
        }

        /// <summary>
        /// 显示的最小X值
        /// </summary>
        public double MinimalVisibleX { get; set; }

        /// <summary>
        /// 显示的最小Y值
        /// </summary>
        public double MinimalVisibleY { get; set; }

        /// <summary>
        /// 显示的最大X值
        /// </summary>
        public double MaximalVisibleX { get; set; }

        /// <summary>
        /// 显示的最大Y值
        /// </summary>
        public double MaximalVisibleY { get; set; }

        /// <summary>
        /// 取X轴点集合
        /// </summary>
        /// <returns></returns>
        public IEnumerable<double> GetVisibleXPoints()
        {
            for (var x = M.Ceiling(MinimalVisibleX); x <= M.Floor(MaximalVisibleX); x++)
            {
                yield return x;
            }
        }

        /// <summary>
        /// 取Y轴点集合
        /// </summary>
        /// <returns></returns>
        public IEnumerable<double> GetVisibleYPoints()
        {
            for (var y = M.Ceiling(MinimalVisibleY); y <= M.Floor(MaximalVisibleY); y++)
            {
                yield return y;
            }
        }
    }
}
